Programming Ecto by Darin Wilson & Eric Meadows-Jonsson
Author:Darin Wilson & Eric Meadows-Jonsson [Wilson, Darin]
Language: eng
Format: epub
Tags: Pragmatic Bookshelf
Publisher: Pragmatic Bookshelf
Published: 2019-03-31T22:00:00+00:00
Examining the List of Changes So Far
The last value of the returned tuple is supposed to be a list of changes that occurred before the error happened. Let’s take another look at what we got in the last example:
artist = Repo.get_by(Artist, name: "Johnny Hodges")
artist_changeset = Artist.changeset(artist,
%{name: "John Cornelius Hodges"})
invalid_changeset = Artist.changeset(%Artist{},
%{name: nil})
multi =
Multi.new
|> Multi.update(:artist, artist_changeset)
|> Multi.insert(:invalid, invalid_changeset)
Repo.transaction(multi)
#=> {:error, :invalid,
#=> #Ecto.Changeset<
#=> action: :insert,
#=> changes: %{},
#=> errors: [name: {"can't be blank", [validation: :required]}],
#=> data: #MusicDB.Artist<>,
#=> valid?: false
#=> >, %{}}
We got an empty map—that seems surprising. The return value told us that the second operation in the Multi failed, so we would expect to see the result of the first operation in the list of changes so far.
This is because Ecto doesn’t like to waste the database’s time. If the Multi contains operations that use changesets, Ecto first checks to make sure all the changesets are valid. If any are not, Ecto won’t bother running the transaction at all. It just flags the invalid changeset and sends it back to us in the return value. There’s no need to trouble the database with an invalid changeset.
Let’s try a different example so we can see something besides an empty map. We’ll create a new Multi that starts with a successful update. We’ll then force an error by trying to insert a new %Genre{} record with a name that already exists in the database (as you might recall from Working with Constraints, the genres table has a unique index on the name column).
artist = Repo.get_by(Artist, name: "Johnny Hodges")
artist_changeset = Artist.changeset(artist,
%{name: "John Cornelius Hodges"})
genre_changeset =
%Genre{}
|> Ecto.Changeset.cast(%{name: "jazz"}, [:name])
|> Ecto.Changeset.unique_constraint(:name)
multi =
Multi.new
|> Multi.update(:artist, artist_changeset)
|> Multi.insert(:bad_genre, genre_changeset)
Repo.transaction(multi)
#=> {:error, :bad_genre, #Ecto.Changeset< ... >,
#=> %{
#=> artist: %MusicDB.Artist{
#=> __meta__: #Ecto.Schema.Metadata<:loaded, "artists">,
#=> albums: #Ecto.Association.NotLoaded<association
#=> :albums is not loaded>,
#=> birth_date: nil,
#=> death_date: nil,
#=> id: 4,
#=> inserted_at: ~N[2018-03-23 14:02:28],
#=> name: "John Cornelius Hodges",
#=> tracks: #Ecto.Association.NotLoaded<association
#=> :tracks is not loaded>,
#=> updated_at: ~N[2018-03-23 14:02:28]
#=> }
#=> }}
Now we can get a good look at that last value. The keys in the map correspond to our named Multi functions that have already been run. In this example, we just had the one :artist update so that’s all this map contains. The value of the item is the result of the operation. Here we can see that our “Johnny Hodges” record was updated to “John Cornelius Hodges” as we expected. But because the Multi failed (thanks to the addition of our bad_genre operation), the database rolled back the change. We can confirm that by looking at the database again:
Repo.get_by(Artist, name: "John Cornelius Hodges")
#=> nil
We get no records back when we search for “John Cornelius Hodges,” which confirms that our update was indeed rolled back.
Download
This site does not store any files on its server. We only index and link to content provided by other sites. Please contact the content providers to delete copyright contents if any and email us, we'll remove relevant links or contents immediately.
MicroPython Projects by Jacob Beningo(1728)
Flutter Projects by Simone Alessandria(1695)
Qt 5 and OpenCV 4 Computer Vision Projects by Zhuo Qingliang(1531)
Julia Programming Projects by Adrian Salceanu;(1330)
Julia Programming Projects by Adrian Salceanu(1308)
iOS 12 Programming for Beginners by Craig Clayton(1251)
Learn Kotlin Programming by Stephen Samuel(1196)
Machine Learning for OpenCV 4 by Aditya Sharma(1004)
Laravel: Up and Running: A Framework for Building Modern PHP Apps by Stauffer Matt(955)
Beginning React Native with Hooks by Lim Greg(865)
The Healthy Programmer (for Jan S Morrison) by Joe Kutner(747)
Android Game Programming For Dummies by Derek James(667)
Arduino + Android Projects for the Evil Genius by Simon Monk(630)
Objective-C Programming for Dummies by Neal Goldstein(536)
Xamarin.Forms Projects by Daniel Hindrikes(474)
Making Android Accessories with IOIO by Simon Monk(459)
Coding All-In-One for Dummies by Abraham Nikhil; Abraham Nikhil;(444)
Programming iOS 13 by Matt Neuburg(442)
Building a Virtual Assistant for Raspberry Pi by Tanay Pant(420)
